//
//  Bytes+Ex.swift
//  OBD
//
//  Created by sqkj on 2021/11/9.
//

import Foundation

extension Int {
    func toBytes() -> [UInt8] {
        return withUnsafeBytes(of: self.bigEndian, Array.init)
    }
    // MARK:- 转成 2位byte
    func to2Bytes() -> [UInt8] {
        let UInt = UInt64(Double(self))
        return [UInt8(truncatingIfNeeded: UInt >> 8), UInt8(truncatingIfNeeded: UInt)]
    }
    // MARK:- 转成 4字节的bytes
    func to4Bytes() -> [UInt8] {
        let UInt = UInt32(Double(self))
        return [UInt8(truncatingIfNeeded: UInt >> 24),
                UInt8(truncatingIfNeeded: UInt >> 16),
                UInt8(truncatingIfNeeded: UInt >> 8),
                UInt8(truncatingIfNeeded: UInt)]
    }
    // MARK:- 转成 8位 bytes
    func to8Bytes() -> [UInt8] {
        let UInt = UInt64(Double(self))
        return [UInt8(truncatingIfNeeded: UInt >> 56),
            UInt8(truncatingIfNeeded: UInt >> 48),
            UInt8(truncatingIfNeeded: UInt >> 40),
            UInt8(truncatingIfNeeded: UInt >> 32),
            UInt8(truncatingIfNeeded: UInt >> 24),
            UInt8(truncatingIfNeeded: UInt >> 16),
            UInt8(truncatingIfNeeded: UInt >> 8),
            UInt8(truncatingIfNeeded: UInt)]
    }
}

extension ArraySlice where Element == UInt8 {
    var int: Int {
        let bytes = [UInt8](self)
        var value : UInt32 = 0
        let data = NSData(bytes: bytes, length: bytes.count)
        data.getBytes(&value, length: bytes.count)
        value = UInt32(bigEndian: value)
        return Int(value)
    }
    
    var bool: Bool {
        return self.int == 1
    }
    
    var string: String? {
        return String(bytes: self, encoding: .utf8)
    }
    
    var data: Data? {
        return Data(self)
    }
    
    /// 转十六进制
    var hexString:String? {
        var hexStr = ""
        let bytes = [UInt8](self)
        for index in 0 ..< bytes.count {
            var Str = bytes[index].description
            if Str.count == 1 {
                Str = "0"+Str;
            }else {
                let low = Int(Str)!%16
                let hight = Int(Str)!/16
                Str = hexIntToStr(HexInt: hight) + hexIntToStr(HexInt: low)
            }
            hexStr += Str
        }
        return hexStr
    }
    
    /// 十六转十进制
    var hexToInt:Int?{
        let str = hexString!.uppercased()
        var sum = 0
        for i in str.utf8 {
            sum = sum * 16 + Int(i) - 48 // 0-9 从48开始
            if i >= 65 {                 // A-Z 从65开始，但有初始值10，所以应该是减去55
                sum -= 7
            }
        }
        return sum
    }
    
    func hexIntToStr(HexInt:Int) -> String {
        var Str = ""
        if HexInt>9 {
            switch HexInt{
            case 10:
                Str = "A"
                break
            case 11:
                Str = "B"
                break
            case 12:
                Str = "C"
                break
            case 13:
                Str = "D"
                break
            case 14:
                Str = "E"
                break
            case 15:
                Str = "F"
                break
            default:
                Str = "0"
            }
        }else {
            Str = String(HexInt)
        }
            
        return Str
     }
}

extension Array {
    subscript(start startIndex: Int, length lengthSize: Int) -> ArraySlice<Element> {
        guard startIndex >= 0, startIndex + lengthSize <= self.count else {
            return []
        }
        
        return self[startIndex..<startIndex + lengthSize]
    }
}

extension Array where Element == UInt8{
    var hexString: String {
        return self.compactMap { String(format: "%02x", $0).uppercased() }
        .joined(separator: "")
    }
}

extension Array where Element == UInt32{
    var hexString: String {
        return self.compactMap { String(format: "%02x", $0).uppercased() }
        .joined(separator: "")
    }
}

extension Array where Element == UInt64{
    var hexString: String {
        return self.compactMap { String(format: "%02x", $0).uppercased() }
        .joined(separator: "")
    }
}


extension String {
    var toUInt8:[UInt8]{
        let bytes = [UInt8](self.utf8)
        return bytes
    }
    var toInt16:Int64 {
        return Int64(self,radix: 16)!
    }
    /// 十六转十进制
    var hexToInt:Int?{
        let str = self.uppercased()
        var sum = 0
        for i in str.utf8 {
            sum = sum * 16 + Int(i) - 48 // 0-9 从48开始
            if i >= 65 {                 // A-Z 从65开始，但有初始值10，所以应该是减去55
                sum -= 7
            }
        }
        return sum
    }
    
    func toBytes(_ length: Int = -1, placeholder: UInt8 = 0x00) -> [UInt8] {
        let stringBytes = Array(self.utf8)
        let length = length > 0 ? length : stringBytes.count
        
        var pageNameBytes: [UInt8] = []
        for i in 0..<length {
            if i < stringBytes.count {
                pageNameBytes.append(stringBytes[i])
            } else {
                pageNameBytes.append(placeholder)
            }
        }
        
        return pageNameBytes
    }
    /// 十六进制String(字符串)转Data
    func hexadecimal() -> Data? {
         var data = Data(capacity: self.count / 2)

         let regex = try! NSRegularExpression(pattern: "[0-9a-f]{1,2}", options: .caseInsensitive)
         regex.enumerateMatches(in: self, range: NSMakeRange(0, utf16.count)) { match, flags, stop in
             let byteString = (self as NSString).substring(with: match!.range)
             var num = UInt8(byteString, radix: 16)!
             data.append(&num, count: 1)
         }

         guard data.count > 0 else { return nil }

         return data
     }
    
    // 将16进制字符串转化为 [UInt8]
    // 使用的时候直接初始化出 Data
    // Data(bytes: Array<UInt8>)
    func bytes(from hexStr: String) -> [UInt8] {
        //        print("hexStr:\(hexStr)")
        assert(hexStr.count % 2 == 0, "输入字符串格式不对，8位代表一个字符")
        var bytes = [UInt8]()
        var sum = 0
        // 整形的 utf8 编码范围
        let intRange = 48...57
        // 小写 a~f 的 utf8 的编码范围
        let lowercaseRange = 97...102
        // 大写 A~F 的 utf8 的编码范围
        let uppercasedRange = 65...70
        for (index, c) in hexStr.utf8CString.enumerated() {
            var intC = Int(c.byteSwapped)
            if intC == 0 {
                break
            } else if intRange.contains(intC) {
                intC -= 48
            } else if lowercaseRange.contains(intC) {
                intC -= 87
            } else if uppercasedRange.contains(intC) {
                intC -= 55
            } else {
                assertionFailure("输入字符串格式不对，每个字符都需要在0~9，a~f，A~F内")
            }
            sum = sum * 16 + intC
            // 每两个十六进制字母代表8位，即一个字节
            if index % 2 != 0 {
                bytes.append(UInt8(sum))
                sum = 0
            }
        }
        print(bytes.count)
        return bytes
    }
    var hexaData: Data { .init(hexa) }
    var hexaBytes: [UInt8] { .init(hexa) }
    private var hexa: UnfoldSequence<UInt8, Index> {
        sequence(state: startIndex) { start in
            guard start < self.endIndex else { return nil }
            let end = self.index(start, offsetBy: 2, limitedBy: self.endIndex) ?? self.endIndex
            defer { start = end }
            return UInt8(self[start..<end], radix: 16)
        }
    }
}

extension Data{
    var hexString:String? {
        let hexDigits = Array("0123456789abcdef".utf16)
        var hexChars = [UTF16.CodeUnit]()
        hexChars.reserveCapacity(self.count * 2)
        for byte in self {
            let (index1, index2) = Int(byte).quotientAndRemainder(dividingBy: 16)
            hexChars.insert(hexDigits[index2], at: 0)
            hexChars.insert(hexDigits[index1], at: 0)
        }
        return String(utf16CodeUnits: hexChars, count: hexChars.count)
    }
}


extension Int64 {
    var unsigned: UInt64 {
        let valuePointer = UnsafeMutablePointer<Int64>.allocate(capacity: 1)
        defer {
            valuePointer.deallocate()
        }
 
        valuePointer.pointee = self
 
        return valuePointer.withMemoryRebound(to: UInt64.self,capacity: 1) { $0.pointee }
    }
}
 
extension UInt64 {
    var signed: Int64 {
        let valuePointer = UnsafeMutablePointer<UInt64>.allocate(capacity: 1)
        defer {
            valuePointer.deallocate()
        }
 
        valuePointer.pointee = self
 
        return valuePointer.withMemoryRebound(to: Int64.self,capacity: 1) { $0.pointee }
    }
}
